#include <Arduino.h>
#include <stdlib.h>
#include <string.h>
#include <SerialCommand.h>
#include <U8glib.h>

#define ICO_WIDTH 9
#define ICO_HEIGHT 8


static unsigned char play_icon[] U8G_PROGMEM = {
   0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x0c, 0x00,
   0x04, 0x00, 0x00, 0x00 };


static unsigned char pause_icon[] U8G_PROGMEM = {
   0x00, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6c, 0x00,
   0x6c, 0x00, 0x00, 0x00 };


static unsigned char stop_icon[] U8G_PROGMEM = {
   0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00,
   0x7c, 0x00, 0x00, 0x00 };

U8GLIB_PCD8544 u8g(15, 16, 8, 10, 9);

#define TRUE 1
#define FALSE 0

#define SCROLL_NONE  0
#define SCROLL_LEFT  -1
#define SCROLL_RIGHT 1

#define TITLE_ANIMATE_INTERVAL	180UL
#define TITLE_ANIMATE_START_INTERVAL 1700UL

uint32_t nextWaitInterval;

struct {
  char title[100];
  char volume[3];
  char state[10];
  uint8_t nVolume;
  int8_t titleScrollDirection;
  int16_t titleScrollPosition;
  int16_t titleMinXPosition;
  uint32_t nextTimeStamp;
  struct {
    uint8_t  titleChanged:1;
    uint8_t  volumeChanged:1;
    uint8_t  stateChanged:1;
    uint8_t  titleHasToBeScrolled:1;
  } flags;
} displayStatus;


int RXLED = 17;  // The RX LED has a defined Arduino pin
// The TX LED was not so lucky, we'll need to use pre-defined
// macros (TXLED1, TXLED0) to control that.
// (We could use the same macros for the RX LED too -- RXLED1,
//  and RXLED0.)

SerialCommand sCmd;


void drawInitialScreen( void );
void drawUI( void );
void TITLE();
void VOLUME();
void STATE();
void LED_on();
void LED_off();
void unrecognized_command();

void setup()
{
 Serial.begin(9600); //This pipes to the serial monitor
 while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
 } 

 u8g.setFont(u8g_font_tpssb);

 //prepare the commands we are listening for
 sCmd.addCommand( "ON", LED_on );
 sCmd.addCommand( "OFF", LED_off );
 sCmd.addCommand( "TITLE", TITLE );
 sCmd.addCommand( "VOLUME", VOLUME );
 sCmd.addCommand( "STATE", STATE );
 sCmd.addDefaultHandler( unrecognized_command );

  u8g.firstPage();
  do {
    drawInitialScreen();
  } while( u8g.nextPage() );  

 delay(1000);
 Serial.println("SETUP COMPLETE");
}

void drawInitialScreen( void )
{
 u8g.setFont(u8g_font_tpssb);
 u8g.drawStr( 2, 14, "PulseBox");
 u8g.setFont(u8g_font_lucasfont_alternate);
 u8g.drawStr( 2, 32, "momche.net  ");
}

void drawUI( void )
{
	uint8_t volLen;

	u8g.setFont(u8g_font_tpssb);
	u8g.drawStr( 2, 14, "PulseBox");

//	u8g.setFont(u8g_font_6x10);
        u8g.setFont(u8g_font_lucasfont_alternate);
	if( displayStatus.flags.titleHasToBeScrolled == TRUE )
	{
		displayStatus.titleScrollPosition += displayStatus.titleScrollDirection;
                if( displayStatus.nextTimeStamp == 0 ) displayStatus.nextTimeStamp = millis() + TITLE_ANIMATE_INTERVAL;
		if( displayStatus.titleScrollPosition <= displayStatus.titleMinXPosition )
		{
                  displayStatus.nextTimeStamp += TITLE_ANIMATE_START_INTERVAL;
	          displayStatus.titleScrollDirection = SCROLL_RIGHT;
		}
		else if( displayStatus.titleScrollPosition >= 4 )
		{
                  displayStatus.nextTimeStamp += TITLE_ANIMATE_START_INTERVAL;
	          displayStatus.titleScrollDirection = SCROLL_LEFT;
		}
	}
	u8g.drawStr( displayStatus.titleScrollPosition, 32, displayStatus.title );

        uint8_t *icon;
	if( strcmp( displayStatus.state, "play" ) == 0 )
	{
           icon = play_icon;
	}
	else if( strcmp( displayStatus.state, "stop" ) == 0 )
	{
           icon = stop_icon;
	}
	else if( strcmp( displayStatus.state, "pause" ) == 0 )
	{
           icon = pause_icon;
	}

        u8g.drawXBMP( 64, 6, ICO_WIDTH, ICO_HEIGHT, icon );

	volLen = (84*displayStatus.nVolume)/100; 
	u8g.drawHLine( 0, 45, volLen );
	u8g.drawHLine( 0, 46, volLen );
	u8g.drawHLine( 0, 47, volLen );

	displayStatus.flags.titleChanged = FALSE;
	displayStatus.flags.volumeChanged = FALSE;
	displayStatus.flags.stateChanged = FALSE;
}

void loop()
{
  uint32_t interval = millis();

  sCmd.readSerial();
  if( 
    displayStatus.flags.titleChanged == TRUE	||
    displayStatus.flags.volumeChanged == TRUE ||
    displayStatus.flags.stateChanged == TRUE	||
		( displayStatus.flags.titleHasToBeScrolled == TRUE && ( interval > displayStatus.nextTimeStamp ) )
  )
  {
    displayStatus.nextTimeStamp = 0;
    u8g.firstPage();
    do {
      drawUI();
    } while( u8g.nextPage() );  
  }
}

void TITLE()
{
  strncpy( displayStatus.title, sCmd.next(), sizeof( displayStatus.title ) );
  Serial.println( displayStatus.title );
  displayStatus.flags.titleChanged = TRUE;

  displayStatus.titleScrollPosition = 1;

  if( u8g.getStrWidth( displayStatus.title ) > u8g.getWidth() )
  {
    displayStatus.flags.titleHasToBeScrolled = TRUE;
    displayStatus.titleScrollDirection = SCROLL_RIGHT;
    displayStatus.titleMinXPosition = u8g.getWidth() - u8g.getStrWidth( displayStatus.title ) - 6;
    displayStatus.nextTimeStamp = millis() + TITLE_ANIMATE_START_INTERVAL;
  }
  else
  {
    displayStatus.flags.titleHasToBeScrolled = FALSE;
    displayStatus.titleScrollDirection = SCROLL_NONE;  
  }
}

void VOLUME()
{
  strncpy( displayStatus.volume, sCmd.next(), sizeof( displayStatus.volume ) );
  Serial.println( displayStatus.volume );
  displayStatus.nVolume = atoi( displayStatus.volume );
  displayStatus.flags.volumeChanged = TRUE;
}

void STATE()
{
  strncpy( displayStatus.state, sCmd.next(), sizeof( displayStatus.state ) );
  Serial.println( displayStatus.state );
  displayStatus.flags.stateChanged = TRUE;
}


void LED_on()
{
  TXLED1;
}

void LED_off()
{
  TXLED0;
}

void unrecognized_command()
{
  Serial.println( "Say what?" );
}
